﻿//    Copyright (C) Kherty.  All rights reserved.
#region

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Text;
using System.Windows.Media.TextFormatting;
using OpenLS.Drawing;

#endregion

namespace OpenLS.Spreadsheet.UI.Internals
{
    internal class FormulaTextSource : CellTextSource
    {
        private readonly EditedCell _cell;
        protected readonly TextRunProperties _runProperties;

        public FormulaTextSource(EditedCell cell, ColorScheme colorScheme)
            : this(cell, colorScheme, new CellTextRunProperties(cell, colorScheme))
        {
        }
        public FormulaTextSource(EditedCell cell, ColorScheme colorScheme, TextRunProperties runProperties)
        {
            Contract.Requires(cell != null);
            _cell = cell;
            cell.PropertyChanged += cell_PropertyChanged;
            Text = cell.Text;
            _runProperties = runProperties;
            // ReSharper disable DoNotCallOverridableMethodsInConstructor
            Move(Length);
            // ReSharper restore DoNotCallOverridableMethodsInConstructor

        }

        internal string Text
        {
            get { return _cell.Text; }
            set { _cell.Text = value; }
        }

        public override int Length
        {
            get { return Text.Length; }
        }

        private void cell_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "Text":
                    NotifyPropertyChanged(e.PropertyName);
                    break;
                case "Formula.Text":
                    this.Move(this._cell.Formula.Text.Length);
                    NotifyPropertyChanged(e.PropertyName);
                    break;
            }
        }

        public override string SelectionText
        {
            get
            {
                int min = this.MinIndex;
                int max = this.MaxIndex;
                if (min == max)
                    return string.Empty;
                var result = new StringBuilder();
                int currentIndex = 0;
                foreach (var run in GetRuns())
                {
                    int len = run.Length;
                    if (currentIndex + len <= min)
                    {
                        currentIndex += run.Length;
                        continue;
                    }
                    if (currentIndex >= max)
                        break;
                    int stringMin = Math.Max(min - currentIndex, 0);
                    int stringMax = Math.Min(max - currentIndex, len);
                    result.Append(run.Text.Substring(stringMin, stringMax - stringMin));
                    currentIndex += run.Length;
                }
                return result.ToString();
            }
        }

        protected override IEnumerable<CellTextRun> GetRuns()
        {
            FormulaTextRunProvider p = new FormulaTextRunProvider(_cell, _runProperties);
            return p.GetRuns();
        }


        public override void OnBackspace()
        {
            if (!string.IsNullOrEmpty(_cell.SuggestionRemainingText))
            {
                _cell.RefusesSuggestions = true;
                return;
            }
            int min = MinIndex;
            int max = MaxIndex;
            if (min == max && min > 0)
                min--;
            Text = getSubString(string.Empty, min, max);

            Move(min);
        }

        public override void OnDelete()
        {
            if (!string.IsNullOrEmpty(_cell.SuggestionRemainingText))
            {
                _cell.RefusesSuggestions = true;
                return;
            }
            int min = MinIndex;
            int max = MaxIndex;
            if (min == max && max < Text.Length)
            {
                max++;
                Text = getSubString(string.Empty, min, max);

                Move(min);
                return;
            }
            Text = getSubString(string.Empty, min, max);
            Move(min);
        }
        string getSubString(string text, int firstCut, int lastCut)
        {
            Contract.Requires(firstCut >= 0);
            Contract.Requires(lastCut >= 0);
            Contract.Requires(lastCut >= firstCut);
            string result = Text.Substring(0, firstCut) + text;
            if (Text.Length - lastCut > 0)
                result += Text.Substring(lastCut, Text.Length - lastCut);
            return result;
        }

        public override void OnTextInput(string text)
        {
            //var selectionIndex = SelectionIndex;
            Text = getSubString(text, MinIndex, MaxIndex);
            this._cell.Formula.updateHotReference(MinIndex, MinIndex + text.Length);
            Move(MinIndex + text.Length);
        }
        public override void Move(int newIndex)
        {
            base.Move(newIndex);
            updateEditedCell();
        }

        private void updateEditedCell()
        {
            _cell.Formula.updateHotReference(MinIndex, MaxIndex);
        }

        public override void Select(int index)
        {
            base.Select(index);
            updateEditedCell();
        }
        public override void OnToggleLockReference()
        {
            int index = SelectionIndex;
            int i = 0;
            foreach (FormulaToken token in _cell.Formula.Tokens)
            {
                if (token is FormulaReference && i + token.Text.Length <= index)
                {
                    ((FormulaReference)token).ToggleLock();
                    return;
                }
            }
        }
    }
}